<?php
    /**
     * Seleção: Classe para gerenciar o fluxo de Seleção
     * @author bruno
     * @since 18/02/2010
     */
    class Selecao extends BaseModel
    {
        protected $selecaoid;
        protected $vagaid;
        protected $dataselecao;
        protected $ativo;
        
        const tablename = "selecoes";
        const tablekey = "selecaoid";
        const tablesequence = "selecoes_selecaoid_seq";

        /**
         * Ajusta as datas e salva a seleção
         * @see model/BaseModel#salvar()
         */
        public function salvar()
        {
            $this->dataselecao = TUtils::DataPtEn( $this->dataselecao );
            
            parent::salvar();
        }
        
        /**
         * Retorna os candidatos vinculados à seleção
         * @return Candidato[]
         */
        public function getCandidatos()
        {
            $criterio = array();
            $criterio['precondicao'] = 'ativo IS TRUE';
            $criterio['campo'] = 'selecaoid';
            $criterio['operador'] = '=';
            $criterio['valor'] = $this->selecaoid;
            
            $selecaoCandidato = new SelecaoCandidato();
            $result = $selecaoCandidato->listar( $criterio );
            
            if ( pg_num_rows( $result ) > 0 ){
                return pg_fetch_all( $result );
            }
            return array();
        }
        
        public function getCandidato()
        {
            $criterio = array();
            $criterio['precondicao']   = 'ativo IS TRUE';
            $criterio['campo']         = 'selecaoid';
            $criterio['operador']      = '=';
            $criterio['valor']         = $this->selecaoid;
            $criterio['limit']         = 1;
            
            $selecaoCandidato = new SelecaoCandidato();
            $result = $selecaoCandidato->listar( $criterio );
            
            $selecaocandidatoid = NULL;
            
            if ( pg_num_rows( $result ) == 1 ){
                $result = pg_fetch_object( $result );
                $selecaocandidatoid = $result->selecaocandidatoid;
            }
            return new SelecaoCandidato( $selecaocandidatoid );
        }
        
        public function getCandidatoSelecionado()
        {
            $criterio = array();
            $criterio['precondicao']   = 'ativo IS TRUE AND selecionado IS TRUE';
            $criterio['campo']         = 'selecaoid';
            $criterio['operador']      = '=';
            $criterio['valor']         = $this->selecaoid;
            $criterio['limit']         = 1;
            
            $selecaoCandidato = new SelecaoCandidato();
            $result = $selecaoCandidato->listar( $criterio );
            
            $selecaocandidatoid = NULL;
            
            if ( pg_num_rows( $result ) == 1 ){
                $result = pg_fetch_object( $result );
                $selecaocandidatoid = $result->selecaocandidatoid;
            }
            return new SelecaoCandidato( $selecaocandidatoid );
        }
        
        public function getCandidatoAprovado()
        {
            $candidato = new SelecaoCandidato();
            
            $sql = 'SELECT sch.selecaocandidatoid, sch.selecaocandidatohistoricoid, sc.candidatoid
                    FROM selecoescandidatoshistorico sch
                    JOIN selecoescandidatos sc ON sc.selecaocandidatoid = sch.selecaocandidatoid
                    WHERE sc.selecaoid ='.$this->selecaoid .' and sch.statusid = fnstatusid(\'CANDIDATO APROVADO\')
                    GROUP BY sch.selecaocandidatoid, sch.selecaocandidatohistoricoid, sc.candidatoid
                    HAVING (sch.selecaocandidatohistoricoid IN 
                                    ( SELECT schx.selecaocandidatohistoricoid
                                      FROM selecoescandidatoshistorico schx
                                      WHERE sch.selecaocandidatoid = schx.selecaocandidatoid
                                      ORDER BY schx.dataregistro DESC
                                      LIMIT 1 ));';
            $result = TSqlSelect::customSelect($sql);
            
            if ( pg_num_rows( $result ) == 1 ){
                $obj = pg_fetch_object($result);
                $candidato = new SelecaoCandidato($obj->selecaocandidatoid);
            }            
            return $candidato;            
        }
        
        public function possuiCandidatoSelecionado()
        {
            $criterio = array();
            $criterio['precondicao']   = 'ativo IS TRUE AND selecionado IS TRUE';
            $criterio['campo']         = 'selecaoid';
            $criterio['operador']      = '=';
            $criterio['valor']         = $this->selecaoid;
            $criterio['limit']         = 1;
            
            $selecaoCandidato = new SelecaoCandidato();
            $result = $selecaoCandidato->listar( $criterio );
            
            if ( pg_num_rows( $result ) == 1 ){
                return TRUE;
            }
            return FALSE;
        }
        
        /**
         * Verifica as pré-condições da vaga
         * @param $vagaid
         */
        public function verificarCondicoesVaga( $vagaid )
        {
            $prefixoErro = 'Não é possível executar esta operação para esta vaga, pois ';
            
            //0. Seleção Ativa
            if ( $this->getTableKeyValue() AND $this->ativo === 'f' ){
                throw new Exception ( $prefixoErro . 'esta seleção não está ativa.' );
            }
            
            //1. Contrato Finalizado
            $vaga = new Vaga( $vagaid );
            $contrato = new Contrato( $vaga->contratoid );
            
            if ( $contrato->statusid != Status::Contrato_CadastroConfirmado ){
                throw new Exception ( $prefixoErro . 'seu contrato não está confirmado.' );
            }
            
            //2. Vaga Lotada
            if ( $vaga->lotacaoid == NULL ){
                throw new Exception ( $prefixoErro . 'ela não está lotada.' );
            }
            
            //4. Vaga Ativa
            if ( $vaga->ativa == FALSE ){
                throw new Exception ( $prefixoErro . 'ela não está ativa.' );
            }
        }
        
        /**
         * Verifica se o cpf é único no contrato informado
         * @param $cpf
         * @param $contratoid
         */
        public function verificarUnicidadeCpf( $cpf, $contratoid )
        {
            $candidato = new Candidato();
               
            $cpf = TUtils::CpfToNum( $cpf );
            
            $resultSet = $candidato->listar( array ( "campo" => "cpf", "operador" => "=", "valor" => $cpf ) );
            $candidatoRs = pg_fetch_object($resultSet);
			
            # Candidato existe
            if ( pg_num_rows( $resultSet ) > 0 ){
            	$selecaoCandidato = new SelecaoCandidato();
                
                # Verificar se o candidato já está em alguma vaga em contratação
                $resultVaga = $selecaoCandidato->listar( array ( 'precondicao' => 'ativo IS TRUE AND selecionado IS FALSE' ,'campo' => 'candidatoid', 'operador' => '=', 'valor' => $candidatoRs->candidatoid ) );
    			if ( pg_num_rows($resultVaga) > 0 ){
    				throw new Exception( 'Este candidato já está participando de um processo de seleção.' );
    			}
    		}
        }
        
        /**
         * Verifica se existe apenas uma seleção ativa na vaga informada
         * @param $vagaid
         */
        public function verificarUnicidadeSelecaoAtiva( $vagaid )
        {
            $criterio                = array();
            $criterio['precondicao'] = 'ativo IS TRUE';
            if ( $this->selecaoid ){
                $criterio['precondicao'] .= ' AND selecaoid <> ' . $this->selecaoid;
            }
            $criterio['campo']       = 'vagaid';
            $criterio['operador']    = '=';
            $criterio['valor']       = $vagaid;
            
            $result = $this->listar($criterio);
            if ( pg_num_rows( $result ) > 0 ){
                throw new Exception( 'Não é possível abrir um processo de seleção nesta vaga, pois ela já possui uma seleção ativa em andamento.' );
            }
        }
        
        /**
         * Verifica as pré-condições para abrir um processo de seleção
         */
        public function verificarPreCondicoesAbrirProcesso()
        {
            global $usuario;
            
            //1. Operação
            if ( !$usuario->isAuthorized( Operacao::SELECAO_ABRIRPROCESSO ) ){
                throw new Exception( 'Autorização insuficiente para abrir processo.' );
            }
        }
        
        public function verificarVagaEncaminharVinculacao() 
        {
            // Desvinculação Encaminhada ou Vaga desocupada
            $vaga = new Vaga($this->vagaid);
            if ($vaga->statusid == Status::Vaga_Ocupada) {
                $candidatoVaga = $vaga->getCandidatoVagaAtivo();
                
                if ($candidatoVaga->getTableKeyValue()) {
                    $candidato = new Candidato($candidatoVaga->candidatoid);
                    throw new Exception(
                        'Não é possível encaminhar este candidato, pois a vaga 
                        está ocupada pelo funcionário ' . $candidato->nome 
                        . ', e não há um processo de desvinculação finalizado.'
                    );
                }
            }    
        }
        
        /**
         * Abre Vários Processos de Seleção
         * @param $arrayDeVagaIds
         */
        public function abrirVariosProcessos( $arrayDeVagaIds )
        {
            //Pré-Condições -----------------------------------------------------------------------
                
            $this->verificarPreCondicoesAbrirProcesso();
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
                pg_query( conexao::Conectar(), 'begin' );
                
                foreach ( $arrayDeVagaIds as $vagaid ){
                    $this->abrirProcesso( $vagaid, FALSE, FALSE );
                    $this->selecaoid = NULL;
                }
                
                pg_query( conexao::Conectar(), 'commit' );
            }
            catch ( exception $e ){
                pg_query( conexao::Conectar(), 'rollback' );
                throw new Exception( $e->getMessage() );
            }
        }
        
        /**
         * Abre o Processo de Seleção
         * @param $vagaid
         */
        public function abrirProcesso( $vagaid, $usarTransacao = TRUE, $preCondicoes = TRUE )
        {
            //Pré-Condições -----------------------------------------------------------------------
                
            global $usuario;
            
            if ( $preCondicoes ){
                $this->verificarPreCondicoesAbrirProcesso();
            }
                
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $vagaid );
            
            //3. Vaga não pode estar em contratação
            $vaga = new Vaga( $vagaid );
            if ($vaga->statusid == Status::Vaga_EmContratacao 
                OR ($vaga->ativa === 't' AND $vaga->statusid == Status::Vaga_AContratar)) {
                throw new Exception('Não é possível abrir um processo de seleção para a vaga ' . $vaga->vagaid . ', pois ela está em contratação.');
            }
            
            //3. Se a vaga tiver ocupada, status não pode ser encaminhado sem substituição
            if ($vaga->statusid == Status::Vaga_Ocupada) {
                $candidatoVaga = $vaga->getCandidatoVagaAtivo();
                $statusid = $candidatoVaga->getStatusAtual();
                if ($statusid == Status::Devolucao_Encaminhada OR
                    $statusid == Status::Devolucao_Pedido_EncaminhadoSemSubstituicao) {
                    throw new Exception(
                        'Não é possível abrir um processo de seleção para a vaga 
                        ' . $vaga->vagaid . ', pois ela está ocupada e com 
                        desvinculação encaminhada sem substituição.'
                    );        
                } elseif (!$candidatoVaga->isVinculacaoFinalizada()) {
                    throw new Exception(
                        'Não é possível abrir um processo de seleção para a vaga 
                        ' . $vaga->vagaid . ', pois o terceirizado ainda não 
                        finalizou sua vinculação.'
                    );  
                }
                
            }
            
            //4. Verificar se já existe uma seleção ativa para esta vaga
            $this->verificarUnicidadeSelecaoAtiva( $vagaid );
                
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
                if ( $usarTransacao ){
                    pg_query( conexao::Conectar(), 'begin' );
                }
                
                // Insere a Seleção
                $this->vagaid = $vagaid;
                $this->dataselecao = date('Y-m-d');
                $this->ativo = TRUE;
                $this->salvar();
                
                if ( $usarTransacao ){
                    pg_query( conexao::Conectar(), 'commit' );
                }
            } catch ( exception $e ){
                if ( $usarTransacao ){
                    pg_query( conexao::Conectar(), 'rollback' );
                }
                throw new Exception( $e->getMessage() );
            }
            
        }
        
        /**
         * Insere um Candidato no Processo de Seleção
         * @param $camposIniciais: array com os campos iniciais do Candidato (cpf, contato, telefone2)
         */
        public function inserirCandidato( $camposIniciais, $encaminharNucleoCentral = FALSE )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$usuario->isAuthorized( Operacao::SELECAO_INFORMARCANDIDATO ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. CPF
            if ( !isset( $camposIniciais['cpf'] ) ){
                throw new Exception ( 'Por favor, informe o CPF do candidato.' );
            }
            
            //3. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //TODO: Buscar pelo Candidato (CPF), caso exista
            $candidato = new Candidato();
            $candidato->candidatoByCpf( $camposIniciais['cpf'] );
            
            if ( $candidato->candidatoid == NULL ){
                //4.1. Verificar se o contato foi informado
                if ( !isset( $camposIniciais['contato'] ) ){
                    throw new Exception ( 'Por favor, informe o contato do candidato.' );
                }
            } else {
                
                $vaga = new Vaga( $this->vagaid );
                
                //4.2. Verificar se o candidato já está outro processo de seleção
                $this->verificarUnicidadeCpf( $camposIniciais['cpf'], $vaga->contratoid );
            }
            
            if (($candidato->candidatoid == NULL OR $candidato->situacao == 'I') AND !$camposIniciais['nome']) {
                throw new Exception('Por favor, informe o nome do candidato.');
            }
            
            //Fim Pré-Condições -------------------------------------------------------------------
        
            try {
                pg_query( conexao::Conectar(), 'begin' );
                
                if ($candidato->candidatoid == NULL){
                    $candidato->cpf = $camposIniciais['cpf'];
                    $candidato->deficiente = FALSE;
                }
                
                if ($candidato->candidatoid == NULL OR $candidato->situacao == 'I') {
                    $candidato->nome = $camposIniciais['nome'];
                    $candidato->situacao = 'N';
                }
                
                $candidato->contato = $camposIniciais['contato'];
                if ( $camposIniciais['telefone2'] ){
                    $candidato->telefone2 = $camposIniciais['telefone2'];
                }
                $candidato->salvar();
                
                $selecaoCandidato = new SelecaoCandidato();
                $selecaoCandidato->selecaoid = $this->selecaoid;
                $selecaoCandidato->candidatoid = $candidato->candidatoid;
                $selecaoCandidato->ativo = TRUE;
                $selecaoCandidato->selecionado = FALSE;
                $selecaoCandidato->salvar();
                
                if ( $encaminharNucleoCentral ){
                    $this->informarCandidato( $selecaoCandidato->selecaocandidatoid, FALSE );
                }
                
                pg_query( conexao::Conectar(), 'commit' );
            } catch ( exception $e ){
                pg_query( conexao::Conectar(), 'rollback' );
                throw new Exception( $e->getMessage() );
            }
        }
        
        /**
         * Encaminha o Candidato para o Núcleo Central
         * @param $selecaocandidatoid
         * @param $preCondicoesVaga
         */
        public function informarCandidato( $selecaocandidatoid, $preCondicoesVaga = TRUE )
        {
            //Pré-Condições -----------------------------------------------------------------------
            if ( $preCondicoesVaga ){
                global $usuario;
            
                //1. Operação
                if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_INFORMARCANDIDATO ) ){
                    throw new Exception( 'Autorização insuficiente para informar candidato.' );
                }
                
                //2. Condições Vaga
                $this->verificarCondicoesVaga( $this->vagaid );
            }
            
            //3. Status
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            $historicoMaisRecente = $selecaoCandidato->getHistoricoMaisRecente();
            
            //4. Só pode haver um candidato informado na selecao
            if ( count( $this->getCandidatos() ) > 1 ){
                throw new Exception( 'Não é possível informar este candidato, pois já existe um candidato informado nesta seleção.' );
            }
            
            //Se possui historico, já foi informado
            if ( $historicoMaisRecente->statusid != NULL ){
                throw new Exception( 'Este candidato já foi informado.' );
            }
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            $selecaoCandidato->inserirHistorico( Status::Candidato_Informado );
        }
        
        /**
         * Encaminha um array de Candidatos para o Núcleo Central
         * @param $array
         */
        public function informarCandidatos( $array )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$usuario->isAuthorized( Operacao::SELECAO_INFORMARCANDIDATO ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
                pg_query( conexao::Conectar(), 'begin' );
                
                foreach ( $array as $a ){
                    $this->informarCandidato( $a, FALSE );
                }
                
                pg_query( conexao::Conectar(), 'commit' );
            } catch ( exception $e ){
                pg_query( conexao::Conectar(), 'rollback' );
                throw new Exception( $e->getMessage() );
            }
        }
        
        /**
         * Encaminha o Candidato para o Núcleo Gestor (Aprova)
         * @param $selecaocandidatoid
         */
        public function aprovarCandidato( $selecaocandidatoid, $observacao )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
        
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_ENCAMINHARNUCLEOGESTOR ) ){
                throw new Exception( 'Autorização insuficiente para aprovar candidato.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //3. Status
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            $historicoMaisRecente = $selecaoCandidato->getHistoricoMaisRecente();
            
            //4. Só pode haver um candidato na selecao
            if ( count( $this->getCandidatos() ) > 1 ){
                throw new Exception( 'Não é possível informar este candidato, pois já existe um candidato informado nesta seleção.' );
            }
            
            //Status deve ser candidato informado
            if ( $historicoMaisRecente->statusid != Status::Candidato_Informado ){
                throw new Exception( 'Este candidato não pode ser encaminhado neste momento.' );
            }
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
                pg_query( conexao::Conectar(), 'begin' );
                
                $selecaoCandidato->inserirHistorico( Status::Candidato_Aprovado, $observacao );
                
                $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
                $candidato = $selecaoCandidato->getCandidato();
                
                //Salva a situação do cpf do candidato como aprovado
                $candidato->situacao = 'V';
	            $candidato->salvar();
                
                pg_query( conexao::Conectar(), 'commit' );
            } catch ( exception $e ){
                pg_query( conexao::Conectar(), 'rollback' );
                throw new Exception( $e->getMessage() );
            }
        }    
        
        /**
         * Reprova o candidato sem desativar a seleção nem o candidato
         * @param $selecaocandidatoid
         * @param $observacao
         */
        public function recusarCandidato( $selecaocandidatoid, $observacao )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_REPROVARCANDIDATO ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            
            // Grava o Histórico
     	    $selecaoCandidato->inserirHistorico( Status::Candidato_Reprovado, $observacao );
        }
        
        /**
         * Reprova o Candidato e marca o CPF como inválido
         * @param $selecaocandidatoid
         */
        public function reprovarCandidatoCPFInvalido( $selecaocandidatoid, $observacao )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_REPROVARCANDIDATOCPFINVALIDO ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //Fim Pré-Condições -------------------------------------------------------------------

            try {
	            pg_query( conexao::Conectar(), 'begin' );

        		$selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
        		
        		// Desativa o Candidato na Seleção
	         	$selecaoCandidato->ativo = FALSE;
	         	$selecaoCandidato->salvar();
	         	
	         	// Registra o CPF Inválido
	         	$candidato = new Candidato( $selecaoCandidato->candidatoid );
	         	$candidato->situacao = 'I';
        	    $candidato->salvar();
        	    
        	    // Desativa a Seleção
                $this->ativo = FALSE;
                $this->salvar();
	         	
	         	// Grava o Histórico
	         	$selecaoCandidato->inserirHistorico( Status::Candidato_Reprovado, $observacao );
            	
            	pg_query( conexao::Conectar(), 'commit' );
        		
        	} catch ( exception $e ){
        		pg_query( conexao::Conectar(), 'rollback' );
        		throw new Exception($e->getMessage());
        	}
        }
        
        /**
         * Encaminha o Candidato para Vinculação
         * @param $selecaocandidatoid
         */
        public function encaminharCandidatoVinculacao( $selecaocandidatoid, $observacao, $dadosComplementares = NULL )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_ENCAMINHARVINCULACAO ) ){
                throw new Exception( 'Autorização insuficiente para encaminhar candidato para vinculação.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            $candidato = new Candidato( $selecaoCandidato->candidatoid );
            
            //3. Dados Complementares nao preenchidos
            if ( $dadosComplementares == NULL AND $candidato->nascimento == NULL AND $candidato->sexo == NULL AND $candidato->rg == NULL ){
                throw new Exception( 'Não é possível encaminhar este candidato, pois seus dados complementares ainda não foram informados.' );
            }
            
            //4. Desvinculação Encaminhada ou Vaga desocupada
            $this->verificarVagaEncaminharVinculacao();
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
                
                pg_query( conexao::Conectar(), 'begin' );
                
                // Marca o Candidato como Selecionado
                $selecaoCandidato->selecionado = TRUE;
                $selecaoCandidato->vinculacaosugestao = $dadosComplementares['txtVinculacaoSugestao'];
                $selecaoCandidato->salvar();
                
                //Remove a data de vinculação do array
                unset( $dadosComplementares['txtVinculacaoSugestao'] );
                
                //Dados Complementares
                TUtils::preencherObjeto( $candidato, $dadosComplementares );
                $candidato->salvar();
                
                // Insere o Histórico
                $selecaoCandidato->inserirHistorico( Status::Candidato_Selecionado, $observacao );
                
                pg_query( conexao::Conectar(), 'commit' );
                
            } catch ( exception $e ){
                pg_query( conexao::Conectar(), 'rollback' );
        		throw new Exception( $e->getMessage() );
            }
        }
        
        public function vincularCandidato( $selecaocandidatoid, $registroTerceirizada, $dataVinculacao )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_VINCULARCANDIDATO ) ){
                throw new Exception( 'Autorização insuficiente para vincular candidato.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //3. Candidato Selecionado
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            if ( $selecaoCandidato->selecionado !== 't' ){
                throw new Exception( 'Não é possível vincular este candidato, pois ele não está selecionado.' );
            }
            
            //TODO: Verificar se a data de vinculação é válida
            
            // Verificar unicidade do registro terceirizada
            $candidatoVaga = new CandidatoVaga();
            if (!$candidatoVaga->verificarRegistroTerceirizada($this->vagaid, $registroTerceirizada, $selecaoCandidato->candidatoid)){
                throw new Exception( 'Por favor, informe outro número de registro na terceirizada, pois este já está sendo utilizado.' );
            }
            
            // Verificar se a vaga está ocupada
            $vaga = new Vaga( $this->vagaid );
            if ( $vaga->statusid == Status::Vaga_Ocupada ){
                throw new Exception( 'Não é possível vincular este candidato à esta vaga, pois ela já está ocupada.' );
            }
            
            // Verifica se já existe um candidato ativo na vaga
            
            $candidatoVagaAtivo = $vaga->getCandidatoVagaAtivo();
            if ( $candidatoVagaAtivo->candidatovagaid ){
                throw new Exception( 'Não é possível vincular este candidato à esta vaga, pois já existe um candidato a ocupando.' );
            }
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
                pg_query( conexao::Conectar(), 'begin' );
                
                // Finaliza o processo de seleção
                $this->ativo = FALSE;
                $this->salvar();
                
                // Marca a Vaga como Ocupada
                $vaga->statusid = Status::Vaga_Ocupada;
                $vaga->ativa = TRUE;
            	$vaga->salvar();
                
                // Insere o candidato na vaga
                $candidatoVaga->vagaid = $this->vagaid;
                $candidatoVaga->candidatoid = $selecaoCandidato->candidatoid;
                $candidatoVaga->registroterceirizada = $registroTerceirizada;
                $candidatoVaga->admissao = $dataVinculacao;
                $candidatoVaga->ativo = TRUE;
                $candidatoVaga->salvar();
                
                // Insere o Histórico do Candidato na Vaga
                $candidatoVaga->inserirHistorico( Status::Candidato_Contratado );
                
                pg_query( conexao::Conectar(), 'commit' );
            } catch ( exception $e ){
                pg_query( conexao::Conectar(), 'rollback' );
        		throw new Exception( $e->getMessage() );
            }
        }
        
        public function informarNaoComparecimento( $selecaocandidatoid )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
        
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_CANDIDATONAOCOMPARECEU ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //3. Status
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            $historicoMaisRecente = $selecaoCandidato->getHistoricoMaisRecente();
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            $selecaoCandidato->inserirHistorico( Status::Candidato_NaoCompareceu );
        }
        
        public function informarComparecimento( $selecaocandidatoid, $observacao )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
        
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_CONFIRMARNAOCOMPARECIMENTO ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //3. Status
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            $historicoMaisRecente = $selecaoCandidato->getHistoricoMaisRecente();
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            $selecaoCandidato->inserirHistorico( Status::Candidato_Selecionado, $observacao );
        }
        
        public function confirmarNaoComparecimento( $selecaocandidatoid, $observacao )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
        
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_CONFIRMARNAOCOMPARECIMENTO ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //3. Status
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            $historicoMaisRecente = $selecaoCandidato->getHistoricoMaisRecente();
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            $selecaoCandidato->inserirHistorico( Status::Candidato_NaoComparecimentoConfirmado, $observacao );
        }
        
        public function reduzirVagaNoPT( $selecaocandidatoid = NULL, $observacao )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_REDUZIRVAGANOPT ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //2. Verificar se a vaga está ocupada
            $vaga = new Vaga($this->vagaid);
            if ($vaga->statusid == Status::Vaga_Ocupada){
                throw new Exception('Não é possível reduzir esta vaga, pois já existe um terceirizado vinculado à ela.');
            }
            
            //2. Condições Vaga
            $this->verificarCondicoesVaga( $this->vagaid );
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
                pg_query( conexao::Conectar(), 'begin' );
                
                //Resetar a Vaga
                $vaga = new Vaga( $this->vagaid );
                $vaga->resetarVaga( TRUE );
                
                //Desativar a Seleção
                $this->ativo = FALSE;
                $this->salvar();
	        	 		
				// Insere o Histórico
				if ( $selecaocandidatoid ){
				    $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
                    $selecaoCandidato->inserirHistorico( Status::Candidato_ContratacaoCancelada, $observacao );
				}
				
				$selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
                if ($selecaoCandidato->getTableKeyValue()) {
            		// Desativa o Candidato na Seleção
    	         	$selecaoCandidato->ativo = FALSE;
    	         	$selecaoCandidato->salvar();
        		}
                
                pg_query( conexao::Conectar(), 'commit' );
            } catch ( exception $e ){
                pg_query( conexao::Conectar(), 'rollback' );
        		throw new Exception( $e->getMessage() );
            }
        }
        
        public function cancelarSelecao( $selecaocandidatoid )
        {
            //Pré-Condições -----------------------------------------------------------------------
            global $usuario;
            
            //1. Operação
            if ( !$this->isVisible( $selecaocandidatoid, Operacao::SELECAO_CANCELARSELECAO ) ){
                throw new Exception( 'Autorização insuficiente.' );
            }
            
            //Fim Pré-Condições -------------------------------------------------------------------
            
            try {
        		pg_query( conexao::Conectar(), 'begin' );

        		$selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
        		
        		if ($selecaoCandidato->getTableKeyValue()) {
            		// Desativa o Candidato na Seleção
    	         	$selecaoCandidato->ativo = FALSE;
    	         	$selecaoCandidato->salvar();
    	         	
    	         	$selecaoCandidato->inserirHistorico(Status::Candidato_SelecaoCancelada);
        		}
	         	
	         	// Desativa a Seleção
                $this->ativo = FALSE;
                $this->salvar();
                
	         	pg_query( conexao::Conectar(), 'commit' );
        		
        	} catch ( exception $e ){
        		pg_query( conexao::Conectar(), 'rollback' );
        		throw new Exception($e->getMessage());
        	}
        }
        
        public function isVisible( $selecaocandidatoid, $operacao )
        {
            global $usuario, $pfcid;
            
            $selecaoCandidato = new SelecaoCandidato( $selecaocandidatoid );
            $historico = $selecaoCandidato->getHistoricoMaisRecente();
            $status = $historico->statusid;
            
            if ( 
                    $selecaocandidatoid == NULL AND 
                    (
                        $operacao != Operacao::SELECAO_CANCELARSELECAO AND  
                        $operacao != Operacao::SELECAO_REDUZIRVAGANOPT
                    )
                ){
                return FALSE;
            }
            
            if ( !$usuario->isAuthorized( $operacao ) OR $this->ativo == 'f' ){
                return FALSE;
            }
            
            switch( $operacao ){
                case Operacao::SELECAO_ENCAMINHARNUCLEOGESTOR:
                    if ( $status == Status::Candidato_Informado ){
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_REPROVARCANDIDATO:
                    if (
                            (
                                $status == Status::Candidato_Aprovado AND 
                                $pfcid == PerfilComportamental::NucleoGestor
                            ) 
                        ){
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_REPROVARCANDIDATOCPFINVALIDO:
                    $candidato = new Candidato($selecaoCandidato->candidatoid);
                    if (
                            ( 
                                $status == Status::Candidato_Informado AND 
                                $pfcid == PerfilComportamental::Gabinete AND 
                                !$candidato->isContratado()
                            ) 
                        ) {
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_ENCAMINHARVINCULACAO:
                    if ( $status == Status::Candidato_Aprovado ){
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_REDUZIRVAGANOPT:
                    if ( 
                            $status == NULL OR 
                            $status == Status::Candidato_Informado OR 
                            $status == Status::Candidato_Aprovado OR 
                            $status == Status::Candidato_Selecionado OR 
                            $status == Status::Candidato_NaoComparecimentoConfirmado
                        )
                        return TRUE; 
                    break;
                case Operacao::SELECAO_VINCULARCANDIDATO:
                    if ( $status == Status::Candidato_Selecionado ){
                        return TRUE;
                    }
                    break;
                case Operacao::RELATORIOS_FORMULARIOENTREVISTA:
                    if ( $status == Status::Candidato_Aprovado ){
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_CANDIDATONAOCOMPARECEU:
                    if ( $status == Status::Candidato_Selecionado ){
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_CANDIDATOVAICOMPARECER:
                    if ( $status == Status::Candidato_NaoCompareceu ){
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_CONFIRMARNAOCOMPARECIMENTO:
                    if ( $status == Status::Candidato_NaoCompareceu ){
                        return TRUE;
                    }
                    break;
                case Operacao::SELECAO_CANCELARSELECAO:
                    if ( $pfcid == PerfilComportamental::Gabinete ){
                        return TRUE;
                    }
                    break;
            }
            return FALSE;
        }
    }
?>
